package com.zys.sac.core.provider;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;

import java.util.Collection;
import java.util.Optional;

/**
 * Created by zhongjunkai on 2023/8/8.
 */
public abstract class AbstractSacUserAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();
        UserDetails currentUser = userDetailsService.loadUserByUsername(username);
        Optional.ofNullable(currentUser).orElseThrow(() -> new CredentialsExpiredException("用户名或密码错误"));
        if (!currentUser.isAccountNonLocked()) {
            throw new LockedException("账户被锁定");
        }
        if (!currentUser.isEnabled()) {
            throw new DisabledException("账户被禁用");
        }
        if (!currentUser.isAccountNonExpired()) {
            throw new AccountExpiredException("账户已过期");
        }
        doMatchPassword(password, currentUser.getPassword());
        Collection<? extends GrantedAuthority> authorities = currentUser.getAuthorities();
        return new UsernamePasswordAuthenticationToken(currentUser, password, authorities);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }

    /**
     * 密码比对
     *
     * @param password 当前传入的密码
     * @param dbPassword 数据库中存在的密码
     */
    protected abstract void doMatchPassword(String password, String dbPassword);
}
